// 导入模块
const { app, BrowserWindow, ipcMain, Tray, Menu, dialog } = require('electron')
const path = require('path')
const fs = require('fs')
const { spawn, exec } = require('child_process');
const db = require('./db.js');
const XLSX = require('xlsx');
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
// 配置表：key 为表名，value 为字段类型定义（string/number）
const FIELD_TYPE_CONFIG = {
    customer: {
        type: 'number',
        name: 'string',
        tray: 'string',
        packType: 'string',
        boxDesc: 'string',
        trayDesc: 'string',
        packStrap: 'string',
        wrappingFilm: 'string',
    },
    material: {
        customerId: 'number',
        name: 'string',
    },
    // 可扩展其他表...
};
async function initData() {
    // 检查表是否存在，不存在则创建
    const hasCustomerTable = await db.schema.hasTable('customer');
    if (!hasCustomerTable) {
        await db.schema.createTable('customer', (table) => {
            table.increments('id').primary(); // 自增主键
            table.integer('type').unsigned(); // 发货类型类型 1外贸集装箱，2内贸集装箱，3国内卡车，
            table.string('name').notNullable();// 客户名称
            table.string('tray').notNullable();// 托盘
            table.string('packType').notNullable(); // 包装样式
            table.string('boxDesc').notNullable(); // 箱标签
            table.string('trayDesc').notNullable(); // 托标签
            table.string('packStrap').notNullable(); // 打包带
            table.string('wrappingFilm').notNullable(); // 缠绕膜
            table.string('path'); //写真文件保存路径
            table.timestamp('created_at').defaultTo(db.fn.now()); // 创建时间
        });
        const data = require("./customerData.js")
        await insertData("customer", data)

        console.log('Custmoer table create success');
    }
    const hasMaterialTable = await db.schema.hasTable('material');
    if (!hasMaterialTable) {
        await db.schema.createTable('material', (table) => {
            table.increments('id').primary(); // 自增主键
            table.bigint("customerId").notNullable();//客户ID
            table.string('name').notNullable(); // 品番
            table.integer('boxQty').unsigned(); //箱收容数
            table.integer('boxTrayQty').unsigned(); //箱数/托
            table.integer('trayQty').unsigned(); //托收容数
            table.timestamp('created_at').defaultTo(db.fn.now()); // 创建时间
        });
        const data = require("./materialData.js")

        for (let i = 0; i < data.length; i++) {
            let customer = await db("customer").where({ name: data[i].customerName }).first();
            if (!customer) {
                continue;
            }
            let obj = {
                customerId: customer.id,
                name: data[i].name,
                boxQty: data[i].boxQty,
                boxTrayQty: data[i].boxTrayQty,
                trayQty: data[i].trayQty
            }
            await insertData("material", [obj])
        }
        console.log('Material table create success');
    }
}

const safeStringify = (data) => {
    const cache = new WeakSet();
    return JSON.parse(JSON.stringify(data, (key, value) => {
        if (typeof value === 'object' && value !== null) {
            if (cache.has(value)) return; // 过滤循环引用
            cache.add(value);
        }
        if (typeof value === 'function') return; // 过滤函数
        return value;
    }));
};

// 2. 插入数据（支持单条/批量插入）
async function insertData(tableName, datas) {
    await db.transaction(async (trx) => {
        await trx(tableName).insert(datas);
    });
}
// 修改数据
async function updateData(tableName, data) {
    await db.transaction(async (trx) => {
        await trx(tableName).where('id', data.id).update(data);
    });
}

// 删除数据
async function removeData(tableName, data) {
    await db.transaction(async (trx) => {
        await trx(tableName).where('id', data.id).del();
    });
}

//分页查询
async function getByPage(tableName, query) {
    if (!query.pageNum) {
        query.pageNum = 1;
    }
    if (!query.pageSize) {
        query.pageSize = 10
    }
    try {
        let fieldTypeMap = FIELD_TYPE_CONFIG[tableName] || {}
        let offset = (query.pageNum - 1) * query.pageSize;
        let queryObj = db(tableName);
        let fields = Object.keys(query)
        let totalQuery = queryObj.clone(); // 克隆条件
        queryObj = queryObj.where((builder) => {
            fields.forEach((field, index) => {
                if (['pageSize', 'pageNum'].includes(field) || !query[field]) {
                    return; // forEach 中 return 等效于 continue
                }
                const fieldType = fieldTypeMap[field] || undefined; // 字段类型（默认字符串）
                if (fieldType == "number") {
                    const condition = builder.where(field, query[field]);
                }
                if (fieldType == "string") {
                    const condition = builder.where(field, 'like', `%${query[field]}%`);
                }

            });
        });
        let list = await queryObj
            .select('*')
            .orderBy('created_at', 'desc') // 按创建时间倒序
            .limit(query.pageSize)
            .offset(offset);
        // 格式化数据（日期和ID类型转换）
        list = list.map(user => ({
            ...user,
            created_at: user.created_at ? user.created_at.toString() : null,
            id: Number(user.id),
        }));
        // ✅ 查询总条数（复用查询条件，避免数据不一致）
        let total = await totalQuery.count('id as total').first();
        return safeStringify({
            data: list, // 当前页数据数组
            pagination: {
                pageNum: query.pageNum, // 当前页码
                pageSize: query.pageSize, // 每页条数
                total: Number(total.total), // 总条数
                totalPages: Math.ceil(total.total / query.pageSize), // 总页数
            },
        });
    } catch (error) {
        console.error('error:', error);
        throw new Error('数据库查询异常');
    }
}


//分页查询
async function getList(tableName, query) {

    try {
        let fieldTypeMap = FIELD_TYPE_CONFIG[tableName] || {}
        let queryObj = db(tableName);
        let fields = Object.keys(query)
        queryObj = queryObj.where((builder) => {
            fields.forEach((field, index) => {
                if (['pageSize', 'pageNum'].includes(field) || !query[field]) {
                    return;
                }
                const fieldType = fieldTypeMap[field] || undefined; // 字段类型（默认字符串）
                if (fieldType == "number") {
                    const condition = builder.where(field, query[field]);
                }
                if (fieldType == "string") {
                    const condition = builder.where(field, 'like', `%${query[field]}%`);
                }
            });
        });
        let list = await queryObj.select('*');
        list = list.map(user => ({
            ...user,
            created_at: user.created_at ? user.created_at.toString() : null,
            id: Number(user.id), // 或 user.id.toString()
        }));

        return list;
    } catch (error) {
        console.error('error:', error);
        throw new Error('数据库查询异常');
    }
}

let isStart = false;
initData();

// 创建主窗口
const createWindow = () => {
    const mainWindow = new BrowserWindow({
        icon: path.join(__dirname, '../dist/favicon.ico'),
        width: 1500,
        height: 800,
        center: true, // 窗口居中显示
        show: true, // 初始隐藏
        // transparent: true, // 设置窗口透明
        frame: false, //是否显示顶部导航，去掉关闭按钮 最大化最小化按钮
        // titleBarStyle: "hidden", //Windows下创建的窗口是否带边框
        // titleBarStyle: "hiddenInset", // MacOS下使用内嵌式无边框样式
        // backgroundColor: "#02243B", // 窗口背景

        webPreferences: {
            sandbox: false,
            preload: path.join(__dirname, 'preload.js'),
            nodeIntegration: false, //开启true这一步很重要,目的是为了vue文件中可以引入node和electron相关的API
            contextIsolation: true, // 可以使用require方法 // 是否在独立 JavaScript 环境中运行
            enableRemoteModule: true, // 可以使用remote方法
            webSecurity: false, // 它将禁用同源策略 (通常用来测试网站), 如果此选项不是由开发者设置的默认为true
            defaultMonospaceFontSize: 16, //页面字体默认为16
            minimumFontSize: 12, //页面字体最小为12
            // v8CacheOptions: "bypassHeatCheckAndEagerCompile", //v8CacheOptions 强制 blink 使用 v8 代码缓存策略  除了编译是及时的。 默认策略是 code。
        }
    })

    mainWindow.loadURL(
        app.isPackaged
            ? `file://${path.join(__dirname, '../dist/index.html')}`
            : 'http://localhost:80'
    );

    if (app.isPackaged) {
        // 设置开机自启
        app.setLoginItemSettings({
            openAtLogin: false,          // 开启自启动
            openAsHidden: true,         // macOS：隐藏启动
            path: process.execPath,     // 可执行文件路径
        })
    }

    // 打开开发工具
    if (!app.isPackaged) {
        mainWindow.webContents.openDevTools()
    }
    // 设置窗口菜单栏
    // mainWindow.setMenu(null);
    //默认最大化
    // mainWindow.maximize();
    //打开
    // mainWindow.show();

    return mainWindow;
}

let mainWindow;
// 当electron完成初始化
app.whenReady().then(() => {

    // 监听渲染进程发出保存数据请求
    ipcMain.handle('createMaterial', async (event, form) => {

        let existing = await db("material").where({ name: form.name }).where({ customerId: form.customerId }).first();
        if (existing) {
            return { success: false, msg: "品番已在对应客户中存在！" }
        }
        await insertData("material", [form])
        return { success: true, msg: "新增成功！" }
    })

    ipcMain.handle('updateMaterial', async (event, form) => {
        let existing = await db("material").where({ name: form.name }).where({ customerId: form.customerId }).whereNot({ id: form.id }).first();
        if (existing) {
            return { success: false, msg: "品番已在对应客户中存在！" }
        }
        await updateData("material", form)
        return { success: true, msg: "修改成功！" }
    })

    ipcMain.handle('removeMaterial', async (event, form) => {
        await removeData("material", form)
        return { success: true, msg: "删除成功！" }
    })

    ipcMain.handle('tableMaterial', async (event, query) => {
        let result = await getByPage("material", query);
        return result
    })

    ipcMain.handle('listMaterial', async (event, query) => {
        let result = await getList("material", query);
        return result
    })
    // 监听渲染进程发出保存数据请求
    ipcMain.handle('createCustomer', async (event, form) => {
        let existing = await db("customer").where({ name: form.name }).first();
        if (existing) {
            return { success: false, msg: "客户名称已存在！" }
        }
        await insertData("customer", [form])
        return { success: true, msg: "新增成功！" }
    })

    ipcMain.handle('updateCustomer', async (event, form) => {
        let existing = await db("customer").where({ name: form.name }).whereNot({ id: form.id }).first();
        if (existing) {
            return { success: false, msg: "客户名称已存在！" }
        }
        await updateData("customer", form)
        return { success: true, msg: "修改成功！" }
    })

    ipcMain.handle('removeCustomer', async (event, form) => {
        await removeData("customer", form)
        return { success: true, msg: "删除成功！" }
    })

    ipcMain.handle('tableCustomer', async (event, query) => {
        let result = await getByPage("customer", query);
        return result
    })

    ipcMain.handle('listCustomer', async (event, query) => {
        let result = await getList("customer", query);
        return result
    })

    ipcMain.handle('select-file', async () => {
        const result = await dialog.showOpenDialog({
            properties: ['openFile'], // 允许选择单个文件
            filters: [{ name: 'Images/Videos', extensions: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'mp4', 'webm', 'ogg', 'mov', 'avi', 'flv'] }] // 筛选文件类型
        });
        if (!result.canceled) {
            return result.filePaths[0]; // 返回真实本地路径（如 "C:\Users\test.jpg"）
        }
    });

    ipcMain.handle('select-import-file', async () => {
        const result = await dialog.showOpenDialog({
            properties: ['openFile'], // 允许选择单个文件
            filters: [{ name: '导入数据', extensions: ['xls', 'xlsx'] }] // 筛选文件类型
        });
        if (!result.canceled) {
            return result.filePaths[0]; // 返回真实本地路径（如 "C:\Users\test.jpg"）
        }
    });

    ipcMain.on('open-virtual-keyboard', () => {
        // 调用Windows系统虚拟键盘（路径为系统默认）
        console.log(2222, "开启系统虚拟键盘")
        exec('"C:\\Windows\\System32\\osk.exe"', (error) => {
            if (error) {
                console.log('调用虚拟键盘失败:', error);
            }
        });
    });

    // 监听关闭虚拟键盘事件
    ipcMain.on('close-virtual-keyboard', () => {
        // 强制结束系统虚拟键盘进程（osk.exe）
        exec('taskkill /f /im osk.exe', (error, stdout) => {
            if (error) {
                console.log('虚拟键盘未运行或已关闭'); // 进程不存在时正常提示
                return;
            }
            console.log('虚拟键盘已关闭:', stdout);
        });
    });
    // 注册IPC处理函数：保存文件到本地
    ipcMain.on('saveFile', async (event, params) => {
        try {
            let fileName = path.basename(params.filePath);
            let targetPath = path.join(__dirname, 'uploads', Date.now() + "-" + fileName);
            if (!fs.existsSync(path.join(__dirname, 'uploads'))) {
                fs.mkdirSync(path.join(__dirname, 'uploads'), { recursive: true }); // recursive: true 允许创建多级目录
            }
            fs.copyFileSync(params.filePath, targetPath);
            let entity = await db("customer").where({ id: params.id }).first();
            entity.path = targetPath;
            await updateData("customer", entity)
            event.reply('upload-result', { success: true, path: targetPath });
        } catch (err) {
            event.reply('upload-result', { success: false, msg: "保存文件失败！" + err.message });
            throw new Error(`保存失败：${err.message}`);

        }

    });
    ipcMain.handle('parse-excel', async (event, params) => {
        try {
            // 读取 Excel 文件
            const workbook = XLSX.readFile(params.filePath);
            // 解析第一个工作表为 JSON（可指定工作表名称，如 workbook.Sheets['Sheet1']）
            const firstSheetName = workbook.SheetNames[0];
            const worksheet = workbook.Sheets[firstSheetName];
            // 转换为 JSON（header: 1 表示首行为数据行，header: 'A' 表示首行为表头）
            const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
            //TODO: 根据不同的类型，进行不同的业务，1 上传的是客户信息， 2 上传的是品番信息
            let hearder;
            if (params.type == 1) {
                hearder = ["客户名称", "发货类型", "样式", "托盘", "箱标签", "托标签", "打包带", "缠绕膜"]

            } else {
                hearder = ["客户名称", "品番", "箱收容数", "箱数/托", "托收容数"];
            }
            console.log(jsonData, 123)
            for (let i = 1; i < jsonData.length; i++) {
                let valueArr = jsonData[i];
                let entity = {};
                if (params.type == 1) {
                    entity.name = valueArr[0];
                    let existing = await db("customer").where({ name: entity.name }).first();
                    if (existing) {
                        entity = existing;
                    }
                    let typeStr = valueArr[1];
                    entity.type = typeStr == '外贸集装箱' ? 1 : (typeStr == '内贸集装箱' ? 2 : (typeStr == '国内卡车' ? 3 : undefined))
                    entity.packType = valueArr[2];
                    entity.tray = valueArr[3];
                    entity.boxDesc = valueArr[4];
                    entity.trayDesc = valueArr[5];
                    entity.packStrap = valueArr[6];
                    entity.wrappingFilm = valueArr[7];
                    await insertData("customer", [entity])
                } else {
                    entity.name = valueArr[0];
                    let existing = await db("customer").where({ name: valueArr[0] }).first();
                    if (!existing) {
                        return { msg: `客户：${valueArr[0]},不存在！`, success: false };
                    }
                    entity.customerId = existing.id;
                    entity.name = valueArr[1];
                    let existing1 = await db("material").where({ name: valueArr[0] }).where({ customerId: existing.id }).first();
                    if (existing1) {
                        entity = existing1;
                    }
                    entity.boxQty = valueArr[2];
                    entity.boxTrayQty = valueArr[3];
                    entity.trayQty = valueArr[4];
                    await insertData("material", [entity])
                }
            }
            return { msg: "解析成功", success: true };
        } catch (error) {
            console.error('Excel 解析失败:', error);
            return { success: false, msg: error.message };
        }
    });

    ipcMain.handle('generate-excel', async (event, { type, query, fileName }) => {
        try {
            // 创建工作表
            let data = await getList(type == 1 ? "customer" : 'material', query);
            let arr = []
            if (type == 1) {
                arr.push(["客户名称", "发货类型", "样式", "托盘", "箱标签", "托标签", "打包带", "缠绕膜"])

            } else {
                arr.push(["客户名称", "品番", "箱收容数", "箱数/托", "托收容数"])
            }
            if (data) {
                for (let i = 0; i < data.length; i++) {
                    let entity = data[i]
                    if (type == 1) {
                        let typeStr = entity.type == 1 ? "外贸集装箱" : (entity.type == 2 ? "内贸集装箱" : "国内卡车")
                        arr.push([entity.name, typeStr, entity.packType, entity.tray, entity.boxDesc, entity.trayDesc, entity.packStrap, entity.wrappingFilm])
                    } else {
                        let customer = await db("customer").where({ id: entity.customerId }).first();
                        arr.push([customer.name, entity.name, entity.boxQty, entity.boxTrayQty, entity.trayQty])
                    }
                }
            }
            const worksheet = XLSX.utils.aoa_to_sheet(arr); // 数组转工作表
            const workbook = XLSX.utils.book_new();
            XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1'); // 添加工作表
            // 打开保存对话框，让用户选择保存路径
            const { filePath } = await dialog.showSaveDialog({
                title: '保存 Excel 文件',
                defaultPath: path.join(require('os').homedir(), fileName),
                filters: [{ name: 'Excel Files', extensions: ['xlsx', 'xls'] }]
            });

            if (!filePath) return null; // 用户取消保存

            // 写入文件
            XLSX.writeFile(workbook, filePath);
            return filePath; // 返回保存路径
        } catch (error) {
            console.error('Excel 生成失败:', error);
            return null;
        }
    });

    // 下面代码防止多开
    // 尝试获取单实例锁
    const gotTheLock = app.requestSingleInstanceLock();
    if (!gotTheLock) {
        // 如果获取锁失败，说明已有实例运行，直接退出
        app.quit();
        return;
    } else {
        // 获取锁成功，继续创建窗口
        mainWindow = createWindow();
        // 当第二个实例尝试启动时触发
        app.on('second-instance', () => {
            if (mainWindow) {
                mainWindow.show()
                mainWindow.setSkipTaskbar(false);
            }
        })
    }

    // mac 上默认保留一个窗口
    app.on('activate', () => {
        if (BrowserWindow.getAllWindows().length === 0) createWindow()
    })
    // 监听渲染进程发出的关闭窗口请求
    ipcMain.on('close-main-window', (event) => {
        mainWindow.hide();
        event.preventDefault();
        mainWindow.setSkipTaskbar(true);
        // mainWindow.close();
    });
    // 监听渲染进程发出的最小化窗口请求
    ipcMain.on('minimize-main-window', () => {
        mainWindow.minimize();
    });
    // 监听渲染进程发出的最大化窗口请求
    ipcMain.on('maximize-main-window', () => {
        mainWindow.maximize();
    });
    // 监听渲染进程发出的恢复窗口请求
    ipcMain.on('unmaximize-main-window', () => {
        mainWindow.unmaximize();
    });
    // 检测窗口是否是最大化
    ipcMain.handle('is_maximize_status', () => {
        return mainWindow.isMaximized();
    });
    // 监听渲染进程发出窗口移动请求
    ipcMain.on('move-win', (event, pos) => {
        mainWindow.setPosition(pos.posX, pos.posY);
    })
    // __dirname
    ipcMain.handle('__dirname', () => {
        return __dirname;
    });
    // 下载目录
    ipcMain.handle('downloads_path', () => {
        return app.getPath('downloads');
    });

    // 监听窗口最大化的事件，向渲染线程发送事件，maximize为传的值，渲染线程监听window-state-changed事件
    mainWindow.on('maximize', () => {
        mainWindow.webContents.send('window-state-changed', 'maximize');
    });
    // 监听窗口取消最大化的事件
    mainWindow.on('unmaximize', () => {
        mainWindow.webContents.send('window-state-changed', 'unmaximize');
    });



    const downloadControllers = new Map();
    // 监听来自渲染进程的下载请求
    ipcMain.handle('download-file', async (event, url, filename) => {
        try {
            const controller = new AbortController();
            const signal = controller.signal;
            downloadControllers.set(event.sender.id, controller);

            const response = await fetch(url, { signal });
            if (!response.ok) throw new Error('Network response was not ok');
            const contentLength = response.headers.get('content-length');
            let total = contentLength ? parseInt(contentLength, 10) : null;
            let loaded = 0;
            // 获取用户下载目录路径
            const downloadDir = app.getPath('downloads');
            const downloadPath = path.join(downloadDir, filename);
            // 创建写入流
            const writer = fs.createWriteStream(downloadPath);
            // 将响应流管道到文件写入流
            const reader = response.body.getReader();
            const readerPromise = (function read() {
                return reader.read().then(({ done, value }) => {
                    if (done || signal.aborted) {
                        event.sender.send('download-completed', downloadPath); // 下载完成通知
                        writer.end();
                        return;
                    }
                    loaded += value.length;
                    if (total) {
                        event.sender.send('download-progress', (loaded / total) * 100);
                    }
                    writer.write(value, () => {
                        if (writer.error) {
                            throw writer.error;
                        }
                    });
                    return read();
                }).catch((error) => {
                    console.error('Error reading from stream:', error.message);
                    throw error;
                });
            })();
            await readerPromise;
            return 'success'; // 返回一个简单的确认信息
        } catch (error) {
            console.error('Error processing the downloaded file:', error.message);
            throw error;
        }
    });
    // 取消下载
    ipcMain.on('cancel-download', (event) => {
        const controller = downloadControllers.get(event.sender.id);
        if (controller) {
            controller.abort();
            console.log('Download cancellation requested.');
        }
    });
    // 处理来自渲染进程的更新包安装请求
    ipcMain.on('sys_update_install', async (event, installPath) => {
        try {
            // 确保路径是绝对路径
            const absoluteUpdaterPath = path.resolve(installPath);
            // 使用 spawn 启动更新程序
            const updater = spawn(absoluteUpdaterPath, [], {
                detached: true, // 让子进程在父进程退出后继续运行
                stdio: ['ignore'] // 忽略标准输入输出
            });
            // 当更新程序启动后，关闭主窗口
            mainWindow.close();
            // 更新程序将独立运行
            updater.unref();
            console.log('Update started and main window closed.');
        } catch (error) {
            console.error('Failed to start update:', error.message);
            throw error;
        }
    });

    createTray(); // 应用启动即创建托盘

})


// 关闭所有窗口 ： 程序退出 ： windows & linux
app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') app.quit()
})

function createTray() {
    const trayIcon = new Tray(path.join(__dirname, '../dist/favicon.ico'));

    const menu = Menu.buildFromTemplate([
        {
            label: '显示窗口', click: () => {
                mainWindow.show();
                mainWindow.setSkipTaskbar(false);
                // mainWindow.maximize();
            }
        },
        { type: 'separator' },
        { label: '退出', click: () => app.quit() }
    ]);

    trayIcon.setToolTip('Electron应用');
    trayIcon.setContextMenu(menu);

    // 点击托盘图标显示窗口
    trayIcon.on('click', () => {
        mainWindow.show()
        mainWindow.setSkipTaskbar(false);
        // mainWindow.maximize();
    });
}



